在對稱密碼學中,我們徹底解決了資料的機密性與完整性問題。然而,對稱密碼學存在一個天生的架構瓶頸——金鑰分配問題(Key Distribution Problem)。若 N 個節點需要兩兩安全通訊,全網需要維護 O(N^2) 把對稱金鑰,且如何在不安全的通道上首次安全地傳遞這把金鑰,形成了一個「雞生蛋、蛋生雞」的難題。
1977 年,Ron Rivest、Adi Shamir 與 Leonard Adleman 提出了著名的 RSA 演算法,正式開啟了非對稱密碼學(Public-Key Cryptography)的時代。RSA 利用單向陷門函數(Trapdoor One-Way Function)的數學特性,將金鑰拆分為公開金鑰(Public Key)與私有金鑰(Private Key),使通訊雙方無需事先共享秘密即可完成安全通訊。
RSA 的核心建立在質數運算與同餘代數上。其金鑰生成流程如下:
[ 選擇兩個超大質數 p, q ] ───> n = p * q
│
▼
φ(n) = (p - 1) * (q - 1)
│
▼
選擇 e (通常為 65537)
│
▼
計算 d ≡ e⁻¹ (mod φ(n))
│
┌─────────────────┴─────────────────┐
▼ ▼
【公鑰 Public Key】 【私鑰 Private Key】
(e, n) (d, n)
φ(n) = (p - 1)(q - 1)
e * d ≡ 1 mod{φ(n)}
假設明文訊息為一小於 n 的正整數 m(即 m ∈ Z_n):
c ≡ m^e mod n
m ≡ c^d mod n
17 * d ≡ 1 mod 3120 => d = 2753
(核對:17 * 2753 = 46801 = 15 * 3120 + 1)
測試加解密:假設明文數字 m = 65
RSA 的安全性建立在大整數分解難題(Integer Factorization Problem, IFP)的算力複雜度之上:
已知 p, q ───────── 很容易 (正向乘法 O(N²)) ─────────> 已知 n
已知 n ───────── 極度困難 (反向因數分解) ─────────> 推導出 p, q
| 金鑰長度 (Key Size) | 安全等效強度 (Symmetric Equivalent) | 現代資安合規現況 |
|---|---|---|
| 1024 bits | ~80 bits | 極度危險 (已被學術界實質破解,嚴禁使用) |
| 2048 bits | ~112 bits | 最低基準 (符合 NIST 當前標準,過渡期用) |
| 3072 bits | ~128 bits | 推薦標準 (現代企業級生產環境預設) |
| 4096 bits | ~140 bits | 高防護等級 (適用於 Root CA 長期憑證) |
以下展示如何使用標準 Java JCA API 生成安全長度(2048/3072 bits)的 RSA KeyPair,並導出其數學參數:
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
public class RsaKeyPairGeneratorExample {
private static final String ALGORITHM = "RSA";
private static final int KEY_SIZE_BITS = 3072; // 採用 3072 bits 高安全強度
public static void main(String[] args) throws Exception {
System.out.println("正在生成 " + KEY_SIZE_BITS + "-bit RSA 金鑰對...");
// 1. 初始化 KeyPairGenerator
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(ALGORITHM);
keyPairGen.initialize(KEY_SIZE_BITS);
// 2. 生成金鑰對
KeyPair keyPair = keyPairGen.generateKeyPair();
PublicKey pubKey = keyPair.getPublic();
PrivateKey privKey = keyPair.getPrivate();
// 3. 提取 RSA 公鑰數學參數 (e, n)
if (pubKey instanceof RSAPublicKey rsaPubKey) {
System.out.println("\n--- RSA 公鑰 (Public Key) ---");
System.out.println("Modulus (n) 位元長度: " + rsaPubKey.getModulus().bitLength() + " bits");
System.out.println("Public Exponent (e): " + rsaPubKey.getPublicExponent());
}
// 4. 提取 RSA 私鑰數學參數 (d, n)
if (privKey instanceof RSAPrivateCrtKey rsaPrivKey) {
System.out.println("\n--- RSA 私鑰 (Private Key - CRT 格式) ---");
System.out.println("Private Exponent (d) 位元長度: " + rsaPrivKey.getPrivateExponent().bitLength() + " bits");
System.out.println("Prime p 位元長度: " + rsaPrivKey.getPrimeP().bitLength() + " bits");
System.out.println("Prime q 位元長度: " + rsaPrivKey.getPrimeQ().bitLength() + " bits");
}
System.out.println("\n 安全 RSA 金鑰對生成成功!");
}
}